﻿// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/StarrySkyAbilitySystemLibrary.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "StarrySkyAbilityTypes.h"
#include "StarrySkyGameplayTags.h"
#include "AbilitySystem/StarrySkyAttributeSet.h"
#include "Kismet/GameplayStatics.h"
#include "Play/StarrySkyPlayerState.h"
#include "UI/HUD/StarrySkyHUD.h"
#include "UI/WidgetController/AttributeMenuWidgetController.h"
#include "UI/WidgetController/StarrySkyWidgetController.h"

bool UStarrySkyAbilitySystemLibrary::MakeWidgetControllerParams(const UObject* WorldContextObject,
	FWidgetControllerParams& OutWCParams, AStarrySkyHUD*& OutStarrySkyHUD)
{
	if(APlayerController* PC = UGameplayStatics::GetPlayerController(WorldContextObject, 0))
	{
		OutStarrySkyHUD=Cast<AStarrySkyHUD>(PC->GetHUD());
		if(OutStarrySkyHUD)
		{
			AStarrySkyPlayerState* PS = PC->GetPlayerState<AStarrySkyPlayerState>();
			UAbilitySystemComponent* ASC = PS->GetAbilitySystemComponent();
			UAttributeSet* AS = PS->GetAttributeSet();
			OutWCParams.PlayerController = PC;
			OutWCParams.PlayerState = PS;
			OutWCParams.AbilitySystemComponent = ASC;
			OutWCParams.AttributeSet = AS;
			return true;
		}
	}
	return false;
}

UOverlayWidgetController* UStarrySkyAbilitySystemLibrary::GetOverlayWidgetController(const UObject* WorldContextObject)
{
	FWidgetControllerParams WCParams;
	AStarrySkyHUD* StarrySkyHUD;
	if (MakeWidgetControllerParams(WorldContextObject, WCParams, StarrySkyHUD))
	{
		return StarrySkyHUD->GetOverlayWidgetController(WCParams);
	}
	return nullptr;
}

UAttributeMenuWidgetController* UStarrySkyAbilitySystemLibrary::GetAttributeMenuWidgetController(
	const UObject* WorldContextObject)
{
	FWidgetControllerParams WCParams;
	AStarrySkyHUD* StarrySkyHUD;
	if (MakeWidgetControllerParams(WorldContextObject, WCParams, StarrySkyHUD))
	{
		return StarrySkyHUD->GetAttributeMenuWidgetController(WCParams);
	}
	return nullptr;
}

void UStarrySkyAbilitySystemLibrary::GetLivePlayersWithinRadius(const UObject* WorldContextObject,
	TArray<AActor*>& OutOverlappingActors, const TArray<AActor*>& ActorsToIgnore, float Radius,
	const FVector& SphereOrigin)
{
}

bool UStarrySkyAbilitySystemLibrary::IsNotFriend(const AActor* FirstActor, const AActor* SecondActor)
{
	//获取Actor的标签分别是玩家和敌人的bool变量
	const bool bFirstActorIsPlayer = FirstActor->ActorHasTag(FName("Player"));
	const bool bSecondActorIsPlayer = SecondActor->ActorHasTag(FName("Player"));
	const bool bFirstActorIsEnemy = FirstActor->ActorHasTag(FName("Enemy"));
	const bool bSecondActorIsEnemy = SecondActor->ActorHasTag(FName("Enemy"));
	//如果两个都是玩家，两个都是敌人，返回false
	const bool bBothArePlayers=bFirstActorIsPlayer&&bSecondActorIsPlayer;
	const bool bBothAreEnemies=bFirstActorIsEnemy&&bSecondActorIsEnemy;
	const bool bFriends=bBothArePlayers||bBothAreEnemies;
	return !bFriends;
}

FGameplayEffectContextHandle UStarrySkyAbilitySystemLibrary::ApplyDamageEffect(const FDamageEffectParams& DamageEffectParams)
{
	//游戏标签库对象
	const FStarrySkyGameplayTags& GameplayTags = FStarrySkyGameplayTags::Get();
	//获取源Actor
	const AActor* SourceAvatarActor = DamageEffectParams.SourceAbilitySystemComponent->GetAvatarActor();
	//通过源能力组件生产伤害效果上下文
	FGameplayEffectContextHandle EffectContextHandle = DamageEffectParams.SourceAbilitySystemComponent->MakeEffectContext();
	//句柄中设置源对象
	EffectContextHandle.AddSourceObject(SourceAvatarActor);
	
	//通过源能力组件生产伤害效果规范句柄
	const FGameplayEffectSpecHandle SpecHandle = DamageEffectParams.SourceAbilitySystemComponent->MakeOutgoingSpec(DamageEffectParams.DamageGameplayEffectClass,DamageEffectParams.AbilityLevel,EffectContextHandle);

	//设置伤害数值，设置呼叫幅度。用于在 C++ 或蓝图中动态设置 GameplayEffectSpec 中 SetByCaller 类型的数值
	//该函数的作用是将一个指定的 FGameplayTag 对应的 SetByCaller 类型的数值赋值给 GameplayEffectSpec，以便在应用这个效果时可以动态传入数值（例如伤害、治疗量、Debuff 持续时间等）
	UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(SpecHandle, DamageEffectParams.DamageType, DamageEffectParams.BaseDamage);
	//将规范句柄应用到目标能力组件
	DamageEffectParams.TargetAbilitySystemComponent->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data);
	return EffectContextHandle;
}
